// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: zijin

#include "coin2/strategy/util/moving_ohlc.h"

#include <algorithm>
#include <cmath>
#include <deque>
#include <random>
#include <utility>
#include <vector>

#include <gtest/gtest.h>
#include <sys/types.h>

namespace coin2::strategy::util {

int64_t prev_ts = 16'000'000'000LL;

TEST(MovingHighTest, Empty) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingHigh<double>> mh;
  mh = std::make_unique<MovingHigh<double>>(timewindow);

  EXPECT_EQ(mh->Size(), 0);
  EXPECT_EQ(mh->GetWindowSize(), 5);
  EXPECT_EQ(mh->Empty(), true);
  EXPECT_EQ(mh->Get(), 0);
}

TEST(MovingHighTest, Basic_Not_Update) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingHigh<double>> mh;
  mh = std::make_unique<MovingHigh<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  mh->Add(ts + prev_ts, obj);
  EXPECT_EQ(mh->Size(), 1);
  EXPECT_EQ(mh->GetWindowSize(), 5);
  EXPECT_EQ(mh->Empty(), false);
  EXPECT_EQ(mh->Get(), 100);
}

TEST(MovingHighTest, Basic_Not_Update2) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingHigh<double>> mh;
  mh = std::make_unique<MovingHigh<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  mh->Add(ts + prev_ts, obj);
  EXPECT_EQ(mh->Size(), 1);
  EXPECT_EQ(mh->GetWindowSize(), 5);
  EXPECT_EQ(mh->Empty(), false);
  EXPECT_EQ(mh->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 200;
  mh->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mh->Size(), 1);
  EXPECT_EQ(mh->GetWindowSize(), 5);
  EXPECT_EQ(mh->Empty(), false);
  EXPECT_EQ(mh->Get(), 200);
}

TEST(MovingHighTest, Basic_Not_Update3) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingHigh<double>> mh;
  mh = std::make_unique<MovingHigh<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  mh->Add(ts + prev_ts, obj);
  EXPECT_EQ(mh->Size(), 1);
  EXPECT_EQ(mh->GetWindowSize(), 5);
  EXPECT_EQ(mh->Empty(), false);
  EXPECT_EQ(mh->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 50;
  mh->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mh->Size(), 2);
  EXPECT_EQ(mh->GetWindowSize(), 5);
  EXPECT_EQ(mh->Empty(), false);
  EXPECT_EQ(mh->Get(), 100);
}

TEST(MovingHighTest, Basic_Update) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingHigh<double>> mh;
  mh = std::make_unique<MovingHigh<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  mh->Add(ts + prev_ts, obj);
  EXPECT_EQ(mh->Size(), 1);
  EXPECT_EQ(mh->GetWindowSize(), 5);
  EXPECT_EQ(mh->Empty(), false);
  EXPECT_EQ(mh->Get(), 100);

  int64_t ts2 = 11;
  double obj2 = 50;
  mh->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mh->Size(), 1);
  EXPECT_EQ(mh->GetWindowSize(), 5);
  EXPECT_EQ(mh->Empty(), false);
  EXPECT_EQ(mh->Get(), 50);
}

TEST(MemMovingHighTest, Empty) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingHigh<double>> mmh;
  mmh = std::make_unique<MemMovingHigh<double>>(timewindow, merge_window);

  EXPECT_EQ(mmh->Size(), 0);
  EXPECT_EQ(mmh->GetWindowSize(), 5);
  EXPECT_EQ(mmh->Empty(), true);
  EXPECT_EQ(mmh->Ready(), false);
}

TEST(MemMovingHighTest, Basic_Not_Update) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingHigh<double>> mmh;
  mmh = std::make_unique<MemMovingHigh<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mmh->Add(ts + prev_ts, obj);
  EXPECT_EQ(mmh->Size(), 1);
  EXPECT_EQ(mmh->GetWindowSize(), 5);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);
}

TEST(MemMovingHighTest, Basic_Not_Update2) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingHigh<double>> mmh;
  mmh = std::make_unique<MemMovingHigh<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mmh->Add(ts + prev_ts, obj);
  EXPECT_EQ(mmh->Size(), 1);
  EXPECT_EQ(mmh->GetWindowSize(), 5);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 200;
  mmh->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mmh->Size(), 1);
  EXPECT_EQ(mmh->GetWindowSize(), 5);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 200);
}

TEST(MemMovingHighTest, Basic_Not_Update3) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingHigh<double>> mmh;
  mmh = std::make_unique<MemMovingHigh<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mmh->Add(ts + prev_ts, obj);
  EXPECT_EQ(mmh->Size(), 1);
  EXPECT_EQ(mmh->GetWindowSize(), 5);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 50;
  mmh->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mmh->Size(), 2);
  EXPECT_EQ(mmh->GetWindowSize(), 5);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);
}

TEST(MemMovingHighTest, Basic_Update) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingHigh<double>> mmh;
  mmh = std::make_unique<MemMovingHigh<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mmh->Add(ts + prev_ts, obj);
  EXPECT_EQ(mmh->Size(), 1);
  EXPECT_EQ(mmh->GetWindowSize(), 5);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  int64_t ts2 = 11;
  double obj2 = 50;
  mmh->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mmh->Size(), 1);
  EXPECT_EQ(mmh->GetWindowSize(), 5);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 50);
}

TEST(MemMovingHighTest, Intermediate_RemoveLow) {
  int64_t timewindow = 10;
  int merge_window = 2;
  std::unique_ptr<MemMovingHigh<double>> mmh;
  mmh = std::make_unique<MemMovingHigh<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mmh->Add(ts + prev_ts, obj);
  EXPECT_EQ(mmh->Size(), 1);
  EXPECT_EQ(mmh->GetWindowSize(), 10);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 90;
  mmh->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mmh->Size(), 2);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  EXPECT_EQ(mmh->GetLastData(), 90);
  EXPECT_EQ(mmh->GetFirstData(), 100);
  EXPECT_EQ(mmh->GetLastTs(), 16000000002);
  EXPECT_EQ(mmh->GetFirstTs(), 16000000001);

  int64_t ts3 = 4;
  double obj3 = 80;
  mmh->Add(ts3 + prev_ts, obj3);
  EXPECT_EQ(mmh->Size(), 3);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  EXPECT_EQ(mmh->GetLastData(), 80);
  EXPECT_EQ(mmh->GetFirstData(), 100);
  EXPECT_EQ(mmh->GetLastTs(), 16000000004);
  EXPECT_EQ(mmh->GetFirstTs(), 16000000001);

  int64_t ts4 = 6;
  double obj4 = 70;
  mmh->Add(ts4 + prev_ts, obj4);
  EXPECT_EQ(mmh->Size(), 4);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  EXPECT_EQ(mmh->GetLastData(), 70);
  EXPECT_EQ(mmh->GetFirstData(), 100);
  EXPECT_EQ(mmh->GetLastTs(), 16000000006);
  EXPECT_EQ(mmh->GetFirstTs(), 16000000001);

  int64_t ts5 = 8;
  double obj5 = 95;
  mmh->Add(ts5 + prev_ts, obj5);
  EXPECT_EQ(mmh->Size(), 2);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  EXPECT_EQ(mmh->GetLastData(), 95);
  EXPECT_EQ(mmh->GetFirstData(), 100);
  EXPECT_EQ(mmh->GetLastTs(), 16000000008);
  EXPECT_EQ(mmh->GetFirstTs(), 16000000001);
  // pop all lower value and push back

  int64_t ts6 = 9;
  double obj6 = 90;
  mmh->Add(ts6 + prev_ts, obj6);
  EXPECT_EQ(mmh->Size(), 2);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  EXPECT_EQ(mmh->GetLastData(), 95);
  EXPECT_EQ(mmh->GetFirstData(), 100);
  EXPECT_EQ(mmh->GetLastTs(), 16000000008);
  EXPECT_EQ(mmh->GetFirstTs(), 16000000001);
  // do not pop back nor push back
}

TEST(MemMovingHighTest, Intermediate_RemoveLow2) {
  int64_t timewindow = 10;
  int merge_window = 3;
  std::unique_ptr<MemMovingHigh<double>> mmh;
  mmh = std::make_unique<MemMovingHigh<double>>(timewindow, merge_window);

  mmh->Add(1 + prev_ts, 100);
  mmh->Add(2 + prev_ts, 90);
  mmh->Add(3 + prev_ts, 80);
  mmh->Add(4 + prev_ts, 70);
  mmh->Add(6 + prev_ts, 95);
  mmh->Add(7 + prev_ts, 90);
  EXPECT_EQ(mmh->Size(), 2);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  EXPECT_EQ(mmh->GetLastData(), 95);
  EXPECT_EQ(mmh->GetFirstData(), 100);
  EXPECT_EQ(mmh->GetLastTs(), 16000000006);
  EXPECT_EQ(mmh->GetFirstTs(), 16000000001);

  mmh->Add(9 + prev_ts, 90);
  EXPECT_EQ(mmh->Size(), 3);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 100);

  EXPECT_EQ(mmh->GetLastData(), 90);
  EXPECT_EQ(mmh->GetFirstData(), 100);
  EXPECT_EQ(mmh->GetLastTs(), 16000000009);
  EXPECT_EQ(mmh->GetFirstTs(), 16000000001);

  mmh->Add(12 + prev_ts, 85);
  EXPECT_EQ(mmh->Size(), 3);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 95);

  EXPECT_EQ(mmh->GetLastData(), 85);
  EXPECT_EQ(mmh->GetFirstData(), 95);
  EXPECT_EQ(mmh->GetLastTs(), 16000000012);
  EXPECT_EQ(mmh->GetFirstTs(), 16000000006);

  mmh->Add(13 + prev_ts, 80);
  EXPECT_EQ(mmh->Size(), 3);
  EXPECT_EQ(mmh->Empty(), false);
  EXPECT_EQ(mmh->Ready(), false);
  EXPECT_EQ(mmh->Get(), 95);

  EXPECT_EQ(mmh->GetLastData(), 85);
  EXPECT_EQ(mmh->GetFirstData(), 95);
  EXPECT_EQ(mmh->GetLastTs(), 16000000012);
  EXPECT_EQ(mmh->GetFirstTs(), 16000000006);
}

TEST(MovingLowTest, Empty) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingLow<double>> ml;
  ml = std::make_unique<MovingLow<double>>(timewindow);

  EXPECT_EQ(ml->Size(), 0);
  EXPECT_EQ(ml->GetWindowSize(), 5);
  EXPECT_EQ(ml->Empty(), true);
  EXPECT_EQ(ml->Get(), 0);
}

TEST(MovingLowTest, Basic_Not_Update) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingLow<double>> ml;
  ml = std::make_unique<MovingLow<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  ml->Add(ts + prev_ts, obj);
  EXPECT_EQ(ml->Size(), 1);
  EXPECT_EQ(ml->GetWindowSize(), 5);
  EXPECT_EQ(ml->Empty(), false);
  EXPECT_EQ(ml->Get(), 100);
}

TEST(MovingLowTest, Basic_Not_Update2) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingLow<double>> ml;
  ml = std::make_unique<MovingLow<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  ml->Add(ts + prev_ts, obj);
  EXPECT_EQ(ml->Size(), 1);
  EXPECT_EQ(ml->GetWindowSize(), 5);
  EXPECT_EQ(ml->Empty(), false);
  EXPECT_EQ(ml->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 50;
  ml->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(ml->Size(), 1);
  EXPECT_EQ(ml->GetWindowSize(), 5);
  EXPECT_EQ(ml->Empty(), false);
  EXPECT_EQ(ml->Get(), 50);

  EXPECT_EQ(ml->GetLastData(), 50);
  EXPECT_EQ(ml->GetFirstData(), 50);
  EXPECT_EQ(ml->GetLastTs(), 16000000002);
  EXPECT_EQ(ml->GetFirstTs(), 16000000002);
}

TEST(MovingLowTest, Basic_Not_Update3) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingLow<double>> ml;
  ml = std::make_unique<MovingLow<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  ml->Add(ts + prev_ts, obj);
  EXPECT_EQ(ml->Size(), 1);
  EXPECT_EQ(ml->GetWindowSize(), 5);
  EXPECT_EQ(ml->Empty(), false);
  EXPECT_EQ(ml->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 200;
  ml->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(ml->Size(), 2);
  EXPECT_EQ(ml->GetWindowSize(), 5);
  EXPECT_EQ(ml->Empty(), false);
  EXPECT_EQ(ml->Get(), 100);

  EXPECT_EQ(ml->GetLastData(), 200);
  EXPECT_EQ(ml->GetFirstData(), 100);
  EXPECT_EQ(ml->GetLastTs(), 16000000002);
  EXPECT_EQ(ml->GetFirstTs(), 16000000001);
}

TEST(MovingLowTest, Basic_Update) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingLow<double>> ml;
  ml = std::make_unique<MovingLow<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  ml->Add(ts + prev_ts, obj);
  EXPECT_EQ(ml->Size(), 1);
  EXPECT_EQ(ml->GetWindowSize(), 5);
  EXPECT_EQ(ml->Empty(), false);
  EXPECT_EQ(ml->Get(), 100);

  int64_t ts2 = 11;
  double obj2 = 50;
  ml->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(ml->Size(), 1);
  EXPECT_EQ(ml->GetWindowSize(), 5);
  EXPECT_EQ(ml->Empty(), false);
  EXPECT_EQ(ml->Get(), 50);
}

TEST(MemMovingLowTest, Empty) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingLow<double>> mml;
  mml = std::make_unique<MemMovingLow<double>>(timewindow, merge_window);

  EXPECT_EQ(mml->Size(), 0);
  EXPECT_EQ(mml->GetWindowSize(), 5);
  EXPECT_EQ(mml->Empty(), true);
  EXPECT_EQ(mml->Ready(), false);
}

TEST(MemMovingLowTest, Basic_Not_Update) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingLow<double>> mml;
  mml = std::make_unique<MemMovingLow<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mml->Add(ts + prev_ts, obj);
  EXPECT_EQ(mml->Size(), 1);
  EXPECT_EQ(mml->GetWindowSize(), 5);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);
}

TEST(MemMovingLowTest, Basic_Not_Update2) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingLow<double>> mml;
  mml = std::make_unique<MemMovingLow<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mml->Add(ts + prev_ts, obj);
  EXPECT_EQ(mml->Size(), 1);
  EXPECT_EQ(mml->GetWindowSize(), 5);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 50;
  mml->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mml->Size(), 1);
  EXPECT_EQ(mml->GetWindowSize(), 5);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 50);

  EXPECT_EQ(mml->GetLastData(), 50);
  EXPECT_EQ(mml->GetFirstData(), 50);
  EXPECT_EQ(mml->GetLastTs(), 16000000002);
  EXPECT_EQ(mml->GetFirstTs(), 16000000002);
}

TEST(MemMovingLowTest, Basic_Not_Update3) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingLow<double>> mml;
  mml = std::make_unique<MemMovingLow<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mml->Add(ts + prev_ts, obj);
  EXPECT_EQ(mml->Size(), 1);
  EXPECT_EQ(mml->GetWindowSize(), 5);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 200;
  mml->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mml->Size(), 2);
  EXPECT_EQ(mml->GetWindowSize(), 5);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);

  EXPECT_EQ(mml->GetLastData(), 200);
  EXPECT_EQ(mml->GetFirstData(), 100);
  EXPECT_EQ(mml->GetLastTs(), 16000000002);
  EXPECT_EQ(mml->GetFirstTs(), 16000000001);
}

TEST(MemMovingLowTest, Basic_Update) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingLow<double>> mml;
  mml = std::make_unique<MemMovingLow<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mml->Add(ts + prev_ts, obj);
  EXPECT_EQ(mml->Size(), 1);
  EXPECT_EQ(mml->GetWindowSize(), 5);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);

  int64_t ts2 = 11;
  double obj2 = 50;
  mml->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mml->Size(), 1);
  EXPECT_EQ(mml->GetWindowSize(), 5);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 50);
}

TEST(MemMovingLowTest, Intermediate_RemoveHigh) {
  int64_t timewindow = 10;
  int merge_window = 2;
  std::unique_ptr<MemMovingLow<double>> mml;
  mml = std::make_unique<MemMovingLow<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mml->Add(ts + prev_ts, obj);
  EXPECT_EQ(mml->Size(), 1);
  EXPECT_EQ(mml->GetWindowSize(), 10);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 110;
  mml->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mml->Size(), 2);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);

  EXPECT_EQ(mml->GetLastData(), 110);
  EXPECT_EQ(mml->GetFirstData(), 100);
  EXPECT_EQ(mml->GetLastTs(), 16000000002);
  EXPECT_EQ(mml->GetFirstTs(), 16000000001);

  int64_t ts3 = 4;
  double obj3 = 120;
  mml->Add(ts3 + prev_ts, obj3);
  EXPECT_EQ(mml->Size(), 3);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);

  EXPECT_EQ(mml->GetLastData(), 120);
  EXPECT_EQ(mml->GetFirstData(), 100);
  EXPECT_EQ(mml->GetLastTs(), 16000000004);
  EXPECT_EQ(mml->GetFirstTs(), 16000000001);

  int64_t ts4 = 6;
  double obj4 = 130;
  mml->Add(ts4 + prev_ts, obj4);
  EXPECT_EQ(mml->Size(), 4);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);

  EXPECT_EQ(mml->GetLastData(), 130);
  EXPECT_EQ(mml->GetFirstData(), 100);
  EXPECT_EQ(mml->GetLastTs(), 16000000006);
  EXPECT_EQ(mml->GetFirstTs(), 16000000001);

  int64_t ts5 = 8;
  double obj5 = 115;
  mml->Add(ts5 + prev_ts, obj5);
  EXPECT_EQ(mml->Size(), 3);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);

  EXPECT_EQ(mml->GetLastData(), 115);
  EXPECT_EQ(mml->GetFirstData(), 100);
  EXPECT_EQ(mml->GetLastTs(), 16000000008);
  EXPECT_EQ(mml->GetFirstTs(), 16000000001);
  // pop all lower value and push back

  int64_t ts6 = 9;
  double obj6 = 120;
  mml->Add(ts6 + prev_ts, obj6);
  EXPECT_EQ(mml->Size(), 3);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 100);

  EXPECT_EQ(mml->GetLastData(), 115);
  EXPECT_EQ(mml->GetFirstData(), 100);
  EXPECT_EQ(mml->GetLastTs(), 16000000008);
  EXPECT_EQ(mml->GetFirstTs(), 16000000001);
  // do not pop back nor push back
}

TEST(MemMovingLowTest, Intermediate_RemoveHigh2) {
  int64_t timewindow = 10;
  int merge_window = 3;
  std::unique_ptr<MemMovingLow<double>> mml;
  mml = std::make_unique<MemMovingLow<double>>(timewindow, merge_window);

  mml->Add(1 + prev_ts, 110);
  mml->Add(2 + prev_ts, 120);
  mml->Add(3 + prev_ts, 130);
  mml->Add(4 + prev_ts, 115);

  mml->Add(7 + prev_ts, 125);
  EXPECT_EQ(mml->Size(), 3);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 110);

  EXPECT_EQ(mml->GetLastData(), 125);
  EXPECT_EQ(mml->GetFirstData(), 110);
  EXPECT_EQ(mml->GetLastTs(), 16000000007);
  EXPECT_EQ(mml->GetFirstTs(), 16000000001);

  mml->Add(12 + prev_ts, 120);
  EXPECT_EQ(mml->Size(), 2);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 115);

  EXPECT_EQ(mml->GetLastData(), 120);
  EXPECT_EQ(mml->GetFirstData(), 115);
  EXPECT_EQ(mml->GetLastTs(), 16000000012);
  EXPECT_EQ(mml->GetFirstTs(), 16000000004);

  mml->Add(15 + prev_ts, 135);
  EXPECT_EQ(mml->Size(), 2);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 120);

  EXPECT_EQ(mml->GetLastData(), 135);
  EXPECT_EQ(mml->GetFirstData(), 120);
  EXPECT_EQ(mml->GetLastTs(), 16000000015);
  EXPECT_EQ(mml->GetFirstTs(), 16000000012);

  mml->Add(16 + prev_ts, 140);
  EXPECT_EQ(mml->Size(), 2);
  EXPECT_EQ(mml->Empty(), false);
  EXPECT_EQ(mml->Ready(), false);
  EXPECT_EQ(mml->Get(), 120);

  EXPECT_EQ(mml->GetLastData(), 135);
  EXPECT_EQ(mml->GetFirstData(), 120);
  EXPECT_EQ(mml->GetLastTs(), 16000000015);
  EXPECT_EQ(mml->GetFirstTs(), 16000000012);
}

TEST(MovingOpenTest, Empty) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingOpen<double>> mo;
  mo = std::make_unique<MovingOpen<double>>(timewindow);

  EXPECT_EQ(mo->Size(), 0);
  EXPECT_EQ(mo->GetWindowSize(), 5);
  EXPECT_EQ(mo->Empty(), true);
  EXPECT_EQ(mo->Get(), 0);
}

TEST(MovingOpenTest, Basic_Not_Update) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingOpen<double>> mo;
  mo = std::make_unique<MovingOpen<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  mo->Add(ts + prev_ts, obj);
  EXPECT_EQ(mo->Size(), 1);
  EXPECT_EQ(mo->GetWindowSize(), 5);
  EXPECT_EQ(mo->Empty(), false);
  EXPECT_EQ(mo->Get(), 100);
}

TEST(MovingOpenTest, Basic_Not_Update2) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingOpen<double>> mo;
  mo = std::make_unique<MovingOpen<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  mo->Add(ts + prev_ts, obj);
  EXPECT_EQ(mo->Size(), 1);
  EXPECT_EQ(mo->GetWindowSize(), 5);
  EXPECT_EQ(mo->Empty(), false);
  EXPECT_EQ(mo->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 200;
  mo->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mo->Size(), 2);
  EXPECT_EQ(mo->GetWindowSize(), 5);
  EXPECT_EQ(mo->Empty(), false);
  EXPECT_EQ(mo->Get(), 100);

  int64_t ts3 = 3;
  double obj3 = 300;
  mo->Add(ts3 + prev_ts, obj3);
  EXPECT_EQ(mo->Size(), 3);
  EXPECT_EQ(mo->GetWindowSize(), 5);
  EXPECT_EQ(mo->Empty(), false);
  EXPECT_EQ(mo->Get(), 100);

  EXPECT_EQ(mo->GetLastData(), 300);
  EXPECT_EQ(mo->GetFirstData(), 100);
  EXPECT_EQ(mo->GetLastTs(), 16000000003);
  EXPECT_EQ(mo->GetFirstTs(), 16000000001);
}

TEST(MovingOpenTest, Basic_Update) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingOpen<double>> mo;
  mo = std::make_unique<MovingOpen<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  mo->Add(ts + prev_ts, obj);
  EXPECT_EQ(mo->Size(), 1);
  EXPECT_EQ(mo->GetWindowSize(), 5);
  EXPECT_EQ(mo->Empty(), false);
  EXPECT_EQ(mo->Get(), 100);

  int64_t ts2 = 11;
  double obj2 = 200;
  mo->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mo->Size(), 1);
  EXPECT_EQ(mo->GetWindowSize(), 5);
  EXPECT_EQ(mo->Empty(), false);
  EXPECT_EQ(mo->Get(), 200);

  EXPECT_EQ(mo->GetLastData(), 200);
  EXPECT_EQ(mo->GetFirstData(), 200);
  EXPECT_EQ(mo->GetLastTs(), 16000000011);
  EXPECT_EQ(mo->GetFirstTs(), 16000000011);
}

TEST(MemMovingOpenTest, Empty) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingOpen<double>> mmo;
  mmo = std::make_unique<MemMovingOpen<double>>(timewindow, merge_window);

  EXPECT_EQ(mmo->Size(), 0);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), true);
  EXPECT_EQ(mmo->Get(), 0);
}

TEST(MemMovingOpenTest, Basic_Not_Update) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingOpen<double>> mmo;
  mmo = std::make_unique<MemMovingOpen<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mmo->Add(ts + prev_ts, obj);
  EXPECT_EQ(mmo->Size(), 1);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), false);
  EXPECT_EQ(mmo->Get(), 100);
}

TEST(MemMovingOpenTest, Basic_Not_Update2) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingOpen<double>> mmo;
  mmo = std::make_unique<MemMovingOpen<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mmo->Add(ts + prev_ts, obj);
  EXPECT_EQ(mmo->Size(), 1);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), false);
  EXPECT_EQ(mmo->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 200;
  mmo->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mmo->Size(), 2);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), false);
  EXPECT_EQ(mmo->Get(), 100);

  int64_t ts3 = 3;
  double obj3 = 300;
  mmo->Add(ts3 + prev_ts, obj3);
  EXPECT_EQ(mmo->Size(), 2);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), false);
  EXPECT_EQ(mmo->Get(), 100);

  EXPECT_EQ(mmo->GetLastData(), 200);
  EXPECT_EQ(mmo->GetFirstData(), 100);
  EXPECT_EQ(mmo->GetLastTs(), 16000000002);
  EXPECT_EQ(mmo->GetFirstTs(), 16000000001);
}

TEST(MemMovingOpenTest, Basic_Update) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingOpen<double>> mmo;
  mmo = std::make_unique<MemMovingOpen<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mmo->Add(ts + prev_ts, obj);
  EXPECT_EQ(mmo->Size(), 1);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), false);
  EXPECT_EQ(mmo->Get(), 100);

  int64_t ts2 = 11;
  double obj2 = 200;
  mmo->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mmo->Size(), 1);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), false);
  EXPECT_EQ(mmo->Get(), 200);

  EXPECT_EQ(mmo->GetLastData(), 200);
  EXPECT_EQ(mmo->GetFirstData(), 200);
  EXPECT_EQ(mmo->GetLastTs(), 16000000011);
  EXPECT_EQ(mmo->GetFirstTs(), 16000000011);
}

TEST(MemMovingOpenTest, Basic_Pushback) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingOpen<double>> mmo;
  mmo = std::make_unique<MemMovingOpen<double>>(timewindow, merge_window);

  int64_t ts = 1;
  double obj = 100;
  mmo->Add(ts + prev_ts, obj);
  EXPECT_EQ(mmo->Size(), 1);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), false);
  EXPECT_EQ(mmo->Get(), 100);

  int64_t ts2 = 11;
  double obj2 = 200;
  mmo->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mmo->Size(), 1);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), false);
  EXPECT_EQ(mmo->Get(), 200);

  EXPECT_EQ(mmo->GetLastData(), 200);
  EXPECT_EQ(mmo->GetFirstData(), 200);
  EXPECT_EQ(mmo->GetLastTs(), 16000000011);
  EXPECT_EQ(mmo->GetFirstTs(), 16000000011);
}

TEST(MemMovingOpenTest, Not_Pushback) {
  int64_t timewindow = 5;
  int merge_window = 2;
  std::unique_ptr<MemMovingOpen<double>> mmo;
  mmo = std::make_unique<MemMovingOpen<double>>(timewindow, merge_window);

  int64_t ts = 2;
  double obj = 100;
  mmo->Add(ts + prev_ts, obj);
  EXPECT_EQ(mmo->Size(), 1);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), false);
  EXPECT_EQ(mmo->Get(), 100);

  int64_t ts2 = 2;
  double obj2 = 200;
  mmo->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mmo->Size(), 1);
  EXPECT_EQ(mmo->GetWindowSize(), 5);
  EXPECT_EQ(mmo->Empty(), false);
  EXPECT_EQ(mmo->Get(), 100);

  EXPECT_EQ(mmo->GetLastData(), 100);
  EXPECT_EQ(mmo->GetFirstData(), 100);
  EXPECT_EQ(mmo->GetLastTs(), 16000000002);
  EXPECT_EQ(mmo->GetFirstTs(), 16000000002);
}

TEST(MovingCloseTest, Empty) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingClose<double>> mc;
  mc = std::make_unique<MovingClose<double>>(timewindow);

  EXPECT_EQ(mc->Size(), 0);
  EXPECT_EQ(mc->GetWindowSize(), 5);
  EXPECT_EQ(mc->Empty(), true);
}

TEST(MovingCloseTest, Basic) {
  int64_t timewindow = 5;
  std::unique_ptr<MovingClose<double>> mc;
  mc = std::make_unique<MovingClose<double>>(timewindow);

  int64_t ts = 1;
  double obj = 100;
  mc->Add(ts + prev_ts, obj);
  EXPECT_EQ(mc->Size(), 1);
  EXPECT_EQ(mc->GetWindowSize(), 5);
  EXPECT_EQ(mc->Empty(), false);
  EXPECT_EQ(mc->Get(), 100);

  EXPECT_EQ(mc->GetLastData(), 100);
  EXPECT_EQ(mc->GetFirstData(), 100);
  EXPECT_EQ(mc->GetLastTs(), 16000000001);
  EXPECT_EQ(mc->GetFirstTs(), 16000000001);

  int64_t ts2 = 2;
  double obj2 = 200;
  mc->Add(ts2 + prev_ts, obj2);
  EXPECT_EQ(mc->Size(), 1);
  EXPECT_EQ(mc->GetWindowSize(), 5);
  EXPECT_EQ(mc->Empty(), false);
  EXPECT_EQ(mc->Get(), 200);

  EXPECT_EQ(mc->GetLastData(), 200);
  EXPECT_EQ(mc->GetFirstData(), 200);
  EXPECT_EQ(mc->GetLastTs(), 16000000002);
  EXPECT_EQ(mc->GetFirstTs(), 16000000002);

  int64_t ts3 = 3;
  double obj3 = 300;
  mc->Add(ts3 + prev_ts, obj3);
  EXPECT_EQ(mc->Size(), 1);
  EXPECT_EQ(mc->GetWindowSize(), 5);
  EXPECT_EQ(mc->Empty(), false);
  EXPECT_EQ(mc->Get(), 300);

  EXPECT_EQ(mc->GetLastData(), 300);
  EXPECT_EQ(mc->GetFirstData(), 300);
  EXPECT_EQ(mc->GetLastTs(), 16000000003);
  EXPECT_EQ(mc->GetFirstTs(), 16000000003);
}
}  // namespace coin2::strategy::util